package org.warm.meaning.x.base.starter.ress.aop;

import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.net.InetAddress;
import java.util.Arrays;


/**
 * spring boot应用启动完成信息提醒监听器
 *
 * @author WarmMeaning
 * @date 2025-01-02
 */
@Component
public class ApplicationStartedRemindListener implements ApplicationListener<ApplicationStartedEvent> {

    /**
     * 监听应用启动完成事件
     *
     * @param event 启动完成事件
     * @author WarmMeaning
     * @date 2025-01-02
     */
    @Override
    @SneakyThrows
    public void onApplicationEvent(ApplicationStartedEvent event) {
        ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
        // 获取激活的配置文件
        String[] activeProfiles = environment.getActiveProfiles();
        StringBuffer activeProfileBuf = new StringBuffer();
        for (String profile : activeProfiles) {
            activeProfileBuf.append(profile).append(" ");
        }
        // 获取主机地址
        String host = InetAddress.getLocalHost().getHostAddress();
        // 获取应用端口号
        String port = environment.getProperty("local.server.port");
        String path = environment.getProperty("server.servlet.context-path");
        // 获取应用名称
        String applicationName = environment.getProperty("spring.application.name");

        Message applicationNameMsg = new Message("Application name", StringUtils.hasLength(applicationName) ? applicationName : "");
        Message activeProfileMsg = new Message(new StringBuffer("Active profile"), activeProfileBuf);
        Message publicAddressMsg = new Message(new StringBuffer("Public address ip"), new StringBuffer("http://")
                .append(host).append(":").append(port)
                .append(StringUtils.hasLength(path) ? path : ""));
        Message localAddressMsg = new Message(new StringBuffer("Local address ip"), new StringBuffer("http://")
                .append("127.0.0.1").append(":").append(port)
                .append(StringUtils.hasLength(path) ? path : ""));
        print(activeProfileMsg,
                applicationNameMsg,
                publicAddressMsg,
                localAddressMsg);
    }

    /**
     * 打印消息
     *
     * @param messageArr 消息
     * @author WarmMeaning
     * @date 2025-01-02
     */
    private void print(Message... messageArr) {
        if (null == messageArr || messageArr.length == 0) {
            return;
        }
        // 获取所有消息体中最长的头部消息长度
        int maxHeadLength = Arrays.stream(messageArr).max(Message::compareHeadLength).get().getHeadLength();
        // 获取所有消息体中最长的消息长度
        int maxBodyLength = Arrays.stream(messageArr).max(Message::compareBodyLength).get().getBodyLength();
        if (maxHeadLength == 0 && maxBodyLength == 0) {
            return;
        }
        int addedLength = Message.END_STR.length() + Message.HEAD_REF_BODY_STR.length() + Message.END_STR.length();
        // 打印开头
        StringBuffer boundaryBuf = new StringBuffer();
        for (int i = 0; i < maxHeadLength + maxBodyLength + addedLength; i++) {
            boundaryBuf.append("—");
        }
        System.out.println(boundaryBuf);
        // 打印消息
        for (Message message : messageArr) {
            printMessage(message, maxHeadLength, maxBodyLength);
        }
        // 打印结尾
        System.out.println(boundaryBuf);
    }

    /**
     * 打印单个消息体
     *
     * @param message       消息体
     * @param maxHeadLength 最大头部长度
     * @param maxBodyLength 最大消息长度
     * @author WarmMeaning
     * @date 2025-01-02
     */
    private void printMessage(Message message, int maxHeadLength, int maxBodyLength) {
        if (null == message) {
            return;
        }
        StringBuffer sb = new StringBuffer(Message.START_STR)
                .append(message.getHead());
        if (message.getHeadLength() < maxHeadLength) {
            int lastLength = maxHeadLength - message.getHeadLength();
            for (int i = 0; i < lastLength; i++) {
                sb.append(" ");
            }
        }
        sb.append(Message.HEAD_REF_BODY_STR)
                .append(message.getBody());
        if (message.getBodyLength() < maxBodyLength) {
            int lastLength = maxBodyLength - message.getBodyLength();
            for (int i = 0; i < lastLength; i++) {
                sb.append(" ");
            }
        }
        sb.append(Message.END_STR);
        System.out.println(sb);
    }

    /**
     * 消息内部类
     *
     * @author WarmMeaning
     * @date 2025-01-02
     */
    @Data
    public static class Message {

        public static final String START_STR = "| ";

        public static final String HEAD_REF_BODY_STR = " : ";

        public static final String END_STR = " |";

        private StringBuffer head;

        private StringBuffer body;

        public Message(StringBuffer head, StringBuffer body) {
            this.head = head;
            this.body = body;
        }

        public Message(String head, String body) {
            this.head = new StringBuffer(head);
            this.body = new StringBuffer(body);
        }

        public int getHeadLength() {
            return null == head ? 0 : head.length();
        }

        public int getBodyLength() {
            return null == body ? 0 : body.length();
        }

        public int compareHeadLength(Message msg) {
            if (null == msg) {
                return 1;
            }
            if (getHeadLength() > msg.getHeadLength()) {
                return 1;
            } else if (getHeadLength() == msg.getHeadLength()) {
                return 0;
            }
            return -1;
        }

        public int compareBodyLength(Message msg) {
            if (null == msg) {
                return 1;
            }
            if (getBodyLength() > msg.getBodyLength()) {
                return 1;
            } else if (getBodyLength() == msg.getBodyLength()) {
                return 0;
            }
            return -1;
        }

    }

}